package com.lincoln.Client.utils;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public abstract class HotModule {
    public HotModule() {
        modules.putAll(loadDefaultJar());
    }

    //模块工厂
    public Map<String, Class> modules = new HashMap<>();

    public Map<String, Class> getModules() {
        return modules;
    }

    /**
     * 类构造方法结构//new Class[]{String.class, Long.class, String.class}
     *
     * @return
     */
    public abstract Class[] getClassDefine();

    //对claas进行过滤,例如:BaseCmd.class不需要被加载
    public abstract boolean filter(String className);

    /**
     * 加载默认的Jar
     *
     * @return
     */
    public abstract Map<String, Class> loadDefaultJar();

    /**
     * 根据名称取出对应module
     *
     * @param name
     * @return
     */
    public Class getModule(String name) {
        return modules.get(name);
    }

    /**
     * 加载jar包中的class
     *
     * @param path        jar包位置:D:/Test2/out/artifacts/Test2_jar/Test2.jar
     * @param packageName 包名:com.lincoln.Client.game
     * @return
     */
    public Map<String, Class> loadJar(String path, String packageName) {
        Map<String, Class> map = new HashMap<>();
        try {
            JarInputStream jarInputStream = new JarInputStream(new FileInputStream(path));
            JarEntry jarEntry;
            do {
                jarEntry = jarInputStream.getNextJarEntry();
                if (jarEntry != null) {
                    String className = jarEntry.getName();
                    if (className.endsWith(".class") && filter(className)) {
                        className = className.substring(0, className.indexOf(".class"));//test.Test
                        className = className.replaceAll("/", ".");
                        if (className.startsWith(packageName)) {
                            URL url = new URL("file:" + path);
                            URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
                            Class<?> clazz = urlClassLoader.loadClass(className);
                            if (clazz != null) {
                                map.put(clazz.getName().replaceAll(packageName+".",""), clazz);
                            }
                        }
                    }
                }
            } while (jarEntry != null);
            jarInputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            return map;
        }
        return map;
    }

    /**
     * 从class中实例化CMD
     *     * @param classes 类构造方法结构//new Class[]{String.class, Long.class, String.class}

     * @param clazz   class
     * @param objects 传入构造方法的数据//new Object[]{groupName, attrStatus, content}
     * @return
     */
    public <T> T loadModuleObject(Class clazz, Object[] objects) {
        Class[] classes = getClassDefine();
        try {
            Constructor constructor = clazz.getDeclaredConstructor(classes);
            constructor.setAccessible(true);
            T obj = (T) constructor.newInstance(objects);
            return obj;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 读取文件夹下所有jar文件
     *
     * @param filepath
     * @return
     */
    public static List<String> readAllFile(String filepath) {
        List<String> list = new ArrayList<>();
        File file = new File(filepath);
        if (!file.isDirectory()) {
            return list;
        } else if (file.isDirectory()) {
            String[] filelist = file.list();
            for (int i = 0; i < filelist.length; i++) {
                if (!(filelist[i].endsWith(".jar") || filelist[i].endsWith(".JAR"))) {
                    continue;
                }
                File readfile = new File(filepath + "\\" + filelist[i]);
                if (!readfile.isDirectory()) {
                    list.add(readfile.getPath());
                }
            }
            return list;
        }
        return list;
    }
}
